/*
*
* 版权所有 Copyleft(c) 2005
* 刘炯个人工作室 Sharp-Mark Personal Studio
*
* 允许自由使用，复制，修改，传播和贩卖此源程序及其文档，而不必支付任何费用。
* 以上的版权信息必须出现在每一份复制品中。同时这份版权信息和许可声明
* 也必须出现在支持文档中。刘炯个人工作室不对此软件适于那种具体
* 用途做出任何阐述。此代码只作为代码本身提供对其品质不做任何保证。
*
*/

#pragma once

#include <cmath>
#include <algorithm>
using namespace std;
#include "../Shape/vertex.h"

// DDA画线法
static void DDALine( int x0, int y0, int x1, int y1, COLORREF color, CPaintDC& dc );

template<class T>
static void DDALine( CVertex<T> p0, CVertex<T> p1, COLORREF color, CPaintDC& dc )
{DDALine(static_cast<int>(p0.GetX()), static_cast<int>(p0.GetY()), static_cast<int>(p1.GetX()), static_cast<int>(p1.GetY()), color, dc);}

// Bresenham画线法。我的做法
static void BresenhamLine_Sharpmark( int x0, int y0, int x1, int y1, COLORREF color, CPaintDC& dc );

template<class T>
static void BresenhamLine_Sharpmark( CVertex<T> p0, CVertex<T> p1, COLORREF color, CPaintDC& dc )
{BresenhamLine_Sharpmark(static_cast<int>(p0.GetX()), static_cast<int>(p0.GetY()),
						 static_cast<int>(p1.GetX()), static_cast<int>(p1.GetY()), color, dc);}

// 蒯天宇的Bresenham画线法
static void BresenhamLine_Kuai( int x0, int y0, int x1, int y1, COLORREF color, CPaintDC& dc );

template<class T>
static void BresenhamLine_Kuai( CVertex<T> p0, CVertex<T> p1, COLORREF color, CPaintDC& dc )
{BresenhamLine_Kuai(static_cast<int>(p0.GetX()), static_cast<int>(p0.GetY()),
					static_cast<int>(p1.GetX()), static_cast<int>(p1.GetY()), color, dc);}

// 斜率在0~1之间
static void BresenhamLine_Alpha( int x0, int y0, int x1, int y1, COLORREF color, CPaintDC& dc );

// DDA画线法
static void DDALine( int x0, int y0, int x1, int y1, COLORREF color, CPaintDC& dc )
{
	int i;
	float dx, dy, length, x ,y;

	if( fabs( (float)x1 - (float)x0 ) >= fabs( (float)y1 - (float)y0 ) )
	{
		length = fabs( (float)x1 - (float)x0 );
	}
	else 
	{
		length = fabs( (float)y1 - (float)y0 );
	}

	dx = ( x1 - x0 ) / length;
	dy = ( y1 - y0 ) / length;

	i = 1;
	x = static_cast<float>(x0);
	y = static_cast<float>(y0);

	while( i <= length )
	{
		dc.SetPixelV( int ( x + 0.5 ), int( y + 0.5 ), color );

		x += dx;
		y += dy;

		i++;
	}
}

// 斜率在0~1之间
static void BresenhamLine_Alpha( int x0, int y0, int x1, int y1, COLORREF color, CPaintDC& dc )
{
	int x, y;

	int dx = x1 - x0;
	int dy = y1 - y0;

	int d = 2 * dy - dx;

	y = y0;

	for( x = x0; x <= x1; x++ )
	{
		dc.SetPixelV( x, y, color );

		if(d >= 0)
		{
			y++;
			d += 2 * dy - 2 * dx;
		}
		else
		{
			d += 2 * dy;
		}
	}
}

// Bresenham画线法。我的做法
static void BresenhamLine_Sharpmark( int x0, int y0, int x1, int y1, COLORREF color, CPaintDC& dc )
{
	int x, y;

	// 斜率不存在的情况单独处理。
	if ( 0 == (x1 - x0) )
	{
		x = x0;
		if( y0 > y1 ) swap(y0, y1);
		for(y = y0; y <= y1; y++)
		{
			dc.SetPixelV(x, y, color);
		}
		return;
	}

	// 斜率计算
	float k = float(y1 - y0) / float(x1 - x0);

	// 分类讨论k的范围
	if(k > 1.0)			// k > 1
	{
		swap(x0, y0);
		swap(x1, y1);
	}
	else if(k > 0)		// 1 >= k > 0
	{
		// do nothing
	}
	else if(k < -1)		// k < -1
	{
		x0 = -x0;
		x1 = -x1;
		swap(x0, y0);
		swap(x1, y1);
	}
	else if(k < 0)		// -1 <= k < 0
	{
		y0 = -y0;
		y1 = -y1;
	}
	else	// k = 0
	{
		y = y0;
		if( x0 > x1 ) swap(x0, x1);
		for(x = x0; x <= x1; x++)
		{
			dc.SetPixelV(x, y, color);
		}
		return;
	}

	// 转换起点终点
	if ((x1 - x0) < 0 )
	{
		swap(x0, x1);
		swap(y0, y1);
	}

	int dx = x1 - x0;
	int dy = y1 - y0;

	int d = 2 * dy - dx;

	x = x0; y = y0;

	for( ; x <= x1; x++ )
	{
		if(k > 1)
		{
			dc.SetPixelV( y, x, color );
		}
		else if(k > 0)
		{
			dc.SetPixelV( x, y, color );
		}
		else if(k < -1)
		{
			dc.SetPixelV( -y, x, color );
		}
		else if(k < 0)
		{
			dc.SetPixelV( x, -y, color );
		}
		else	// k = 0
		{
			// do nothing;
		}

		if(d >= 0)
		{
			y++;
			d += 2 * dy - 2 * dx;
		}
		else
		{
			d += 2 * dy;
		}
	}
}

//蒯天宇的Bresenham画线法 - 当斜率为负的时候而且在0到-1之间：
static void Draw_Line_XMS(const int x1, const int y1, const int x2, const int y2, COLORREF color, CPaintDC& dc)
{
	int dx, dy, d, x, y, i;

	dx = x2 - x1;
	dy = y2 - y1;

	d = 2 * dy + dx;
	x = x1;
	y = y1;
	for (i = 0; i < dx; i++)
	{
		dc.SetPixelV(x, y, color);
		x++;
		if (d < 0)	//右下方的点:
		{
			d = d + 2 * dy + 2 * dx;
			y--;
		}
		else		//右面的点:
			d = d + 2 * dy;

	}
}
//蒯天宇的Bresenham画线法 - 当斜率为正的时候在0到1之间：
static void Draw_Line_XPS(int x1, int y1, int x2, int y2, COLORREF color, CPaintDC& dc)
{
	//这个也是书上的代码：
	int dx, dy, d, x, y, i;

	dx = x2 - x1;
	dy = y2 - y1;

	d = 2 * dy - dx;

	x = x1;
	y = y1;

	for(i = 0; i < dx; i++)
	{
		dc.SetPixelV(x, y, color);
		x++;
		if(d >= 0)
		{
			//取右上方的点:
			d = d + 2 * dy - 2 * dx;
			y++;
		}
		else
		{
			//右方的点:
			d = d + 2 * dy;
		}
	}
}

//蒯天宇的Bresenham画线法 - 当斜率为负的时候而且在负无穷到-1：
static void Draw_Line_YMB(int x1, int y1, int x2, int y2, COLORREF color, CPaintDC& dc)
{
	int dx, dy, d, x, y, i;
	dx = x2 - x1;
	dy = y2 - y1;
	d = 2 * dx + dy;
	x = x1;
	y = y1;
	for(i = 0; i < dy; i++)
	{
		dc.SetPixelV(x, y, color);
		y++;
		if(d <= 0)//取右点:
		{
			d = d + 2 * dy + 2 * dx;
			x--;
		}
		else//左点
			d = d + 2 * dx;
	}

}
//蒯天宇的Bresenham画线法 - 当斜率在1到正无穷的时候：
static void Draw_Line_YPB(int x1, int y1, int x2, int y2, COLORREF color, CPaintDC& dc)
{
	int dx, dy, d, i, x, y;
	dx = x2 - x1;
	dy = y2 - y1;
	d = 2 * dx - dy;
	x = x1;
	y = y1;
	for (i = 0; i < dy; i++)
	{
		dc.SetPixelV(x, y, color);
		y++;
		if(d >= 0)//右上角的点:
		{
			x++;
			d = d + 2*dx - 2*dy;
		}
		else//左边的点:
			d = d + 2 * dx;
	}
}

//蒯天宇的Bresenham画线法
static void BresenhamLine_Kuai(int x1, int y1,//开始端点 
					 int x2, int y2,//终点端点
					 COLORREF color,//线条颜色
					 CPaintDC& dc)  //绘画上下文
{
	//转化过来:一定要转化，要不结果将被取尾。将不精确。
	float dx = static_cast<float>(x2 - x1);
	float dy = static_cast<float>(y2 - y1);

	float fslope;		//斜率
	fslope = dy / dx;

	if(x1 == x2)			//垂直的时候调用
	{
		if (y1 > y2)
			Draw_Line_YPB(x2, y2, x1, y1, color, dc);
		else
			Draw_Line_YPB(x1, y1, x2, y2, color, dc);
	}
	else				//在斜率不是无穷的时候分类：
	{
		if(fslope >= 0 && fslope <= 1)	//调用靠近X轴而且斜率小于1大于零的函数:
		{
			//按照X轴的坐标排序:
			if (x1 > x2)
				Draw_Line_XPS(x2, y2, x1, y1, color, dc);
			else
				Draw_Line_XPS(x1, y1, x2, y2, color, dc);
		}
		if(fslope < 0 && fslope >= -1)//靠近X轴而且斜率大于-1小于零的时候调用：
		{
			//按照X轴的坐标排序:
			if(x1 > x2)
				Draw_Line_XMS(x2, y2, x1, y1, color, dc);
			else
				Draw_Line_XMS(x1, y1, x2, y2, color, dc);

		}
		if (fslope > 1)		//靠近Y轴而起斜率大于1调用函数： 
		{
			//按照Y轴的坐标排序:
			if (y1 > y2)
				Draw_Line_YPB(x2, y2, x1, y1, color, dc);
			else
				Draw_Line_YPB(x1, y1, x2, y2, color, dc);
		}
		if(fslope < -1)		//靠近Y轴而且斜率小于-1调用函数：
		{
			//按照Y轴的坐标排序:
			if(y1 > y2)
				Draw_Line_YMB(x2, y2, x1, y1, color, dc);
			else
				Draw_Line_YMB(x1, y1, x2, y2, color, dc);
		}
	}
}